#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>


#include <net/if.h>
#include <arpa/inet.h>

#include <errno.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/shm.h>
#include <sys/epoll.h>

#include "socketserver.h"

static int setnonblocking(int fd) {
    int old_option = fcntl(fd, F_GETFL);
    int new_option = old_option | O_NONBLOCK;
    fcntl(fd, F_SETFL, new_option);
    return old_option;
}

//int add_tcp_client(socket_server_config *config, int fd) {
//    if (fd < 0 || config->tcp_clients_cnt >= TCP_CLIENT_MAX) {
//        return -1;
//    }
//
//    for (int i = 0; i < TCP_CLIENT_MAX; i++) {
//        if (config->tcp_clients[i] <= 0) {
//            config->tcp_clients[i] = fd;
//            config->tcp_clients_cnt++;
//            return 0;
//        }
//    }
//    return -1;
//}
//
//int del_tcp_client(socket_server_config *config, int fd) {
//    for (int i = 0; i < TCP_CLIENT_MAX; i++) {
//        if (config->tcp_clients[i] == fd) {
//            config->tcp_clients[i] = -1;
//            config->tcp_clients_cnt--;
//            return 0;
//        }
//    }
//    return -1;
//}

int create_tcp_server(int *fd, const char* ip, int port) {
    struct sockaddr_in address;
    int tcp_listenfd = -1;
    int one = 1;
    int ret = 0;

    if (*fd != -1) {
        close(*fd);
    }

    bzero(&address, sizeof(address));
    address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &address.sin_addr);
    address.sin_port = htons(port);

    tcp_listenfd = socket(PF_INET, SOCK_STREAM, 0);
    if (tcp_listenfd < 0) {
        perror("tcp socket");
        return -1;
    }

    if (setsockopt(tcp_listenfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
        perror("tcp setsockopt");
        close(tcp_listenfd);
        return -1;
    }

    ret = bind(tcp_listenfd, (struct sockaddr*)&address, sizeof(address));
    if (ret != 0) {
        perror("tcp bind");
        close(tcp_listenfd);
        return -1;
    }

    ret = listen(tcp_listenfd, 50);
    if (ret != 0) {
        perror("tcp listen");
        close(tcp_listenfd);
        return -1;
    }

    *fd = tcp_listenfd;
    return 0;
}

int create_udp_server(int *fd, const char* ip, int port) {
    struct sockaddr_in address;
    int udpfd = -1;
    int one = 1;
    int ret = 0;

    if (*fd != -1) {
        close(*fd);
    }

    bzero(&address, sizeof(address));
    address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &address.sin_addr);
    address.sin_port = htons(port);

    udpfd = socket(PF_INET, SOCK_DGRAM, 0);
    if (udpfd < 0) {
        perror("udp socket");
        return -1;
    }

    if (setsockopt(udpfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
        perror("udp setsockopt");
        close(udpfd);
        return -1;
    }

    ret = bind(udpfd, (struct sockaddr*)&address, sizeof(address));
    if (ret == -1) {
        perror("udp bind");
        close(udpfd);
        return -1;
    }

    *fd = udpfd;
    return 0;
}

// 绑定到指定网卡（仅Linux生效）
static int try_bind_socket_to_interface(int sockfd, const char* interface) {
    struct ifreq ifr;
    if(sockfd < 0) {
        return -1;
    }
    if(!interface) {
        return -1;
    }
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, interface, IFNAMSIZ - 1);
    printf("bind sockfd %d to interface %s\n", sockfd, interface);
    return setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
}

static int try_reuse_port(int sockfd, int enable_reuse_port) {
    // 设置端口可重用（避免地址被占用）
    int reuse_port = 1;
    if (!enable_reuse_port) {
        reuse_port = 0;
    }
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_port, sizeof(reuse_port)) < 0) {
        perror("set SO_REUSEADDR failed");
        return -1;
    }

    // Linux下可以设置SO_REUSEPORT允许多个套接字绑定同一个端口
#ifdef SO_REUSEPORT
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &reuse_port, sizeof(reuse_port)) < 0) {
        perror("set SO_REUSEPORT failed");
        return -1;
    }
#endif
    return 0;
}

static int set_recv_timeout(int sockfd, int timeout_sec, int timeout_ms) {
    // 设置接收超时
    struct timeval recv_timeout;
    recv_timeout.tv_sec = timeout_sec;
    recv_timeout.tv_usec = timeout_ms * 1000;
    if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &recv_timeout, sizeof(recv_timeout)) < 0) {
        perror("set SO_RCVTIMEO failed");
    }
    return 0;
}

static int try_enable_udp_broadcast(int sockfd, int enable_udp_broadcast) {
    // 设置端口可重用（避免地址被占用）
    int broadcast = 1;
    if (!enable_udp_broadcast) {
        broadcast = 0;
    }
    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) < 0) {
        perror("set SO_BROADCAST failed");
        return -1;
    }

    return 0;
}


// 寻找可用的客户端连接槽位
int find_empty_slot(int *clients, int max_clients) {
    for (int i = 0; i < max_clients; i++) {
        if (clients[i] == -1) {
            return i;
        }
    }
    return -1;
}

// 从客户端连接列表中移除指定的fd
void remove_client(int *clients, int max_clients, int fd) {
    for (int i = 0; i < max_clients; i++) {
        if (clients[i] == fd) {
            clients[i] = -1;
            break;
        }
    }
}

int socket_server_exec(socket_server_config *config) {
    int tcp_listenfd = -1;
    int udpfd = -1;
    int ret = 0;
    fd_set read_fds;
    fd_set master_fds; // 保存所有需要监听的文件描述符
    struct sockaddr_in client_address;
    socklen_t client_addrlength = sizeof(client_address);
    int enable_tcp   = config->enable_tcp;
    int enable_udp   = config->enable_udp;
    const char *ip   = config->ip;
    int port         = config->port;
    TcpConnectCallback on_tcp_connect        = config->on_tcp_connect;
    TcpDisconnectCallback on_tcp_disconnect  = config->on_tcp_disconnect;
    TcpDataCallback on_tcp_data   = config->on_tcp_data;
    UdpDataCallback on_udp_data   = config->on_udp_data;
    unsigned char *buf_for_recv_tcp   = config->buf_for_recv_tcp;
    int            buf_for_recv_tcp_size = config->buf_for_recv_tcp_size;
    unsigned char *buf_for_recv_udp   = config->buf_for_recv_udp;
    int            buf_for_recv_udp_size = config->buf_for_recv_udp_size;

    // 用于存储TCP客户端连接
    int tcp_clients[TCP_CLIENT_MAX] = {-1};
    int max_fd = 0; // 记录最大的文件描述符，用于select
    struct timeval tv; // select超时设置

    if(config == NULL) {
        return -1;
    }

//init:
    // 初始化客户端连接数组
    memset(tcp_clients, -1, sizeof(tcp_clients));

    // 关闭之前的连接
    if (tcp_listenfd != -1) close(tcp_listenfd);
    if (udpfd != -1) close(udpfd);

    tcp_listenfd = -1;
    udpfd = -1;
    max_fd = 0;

    // Initialize TCP server if enabled
    if (enable_tcp) {
        if (create_tcp_server(&tcp_listenfd, ip, port) != 0) {
            fprintf(stderr, "Failed to create TCP server\n");
            return -1;
        }
        // 绑定到指定网卡（如果有）
        if (try_bind_socket_to_interface(tcp_listenfd, config->bind_to_interface) != 0) {
            perror("bind tcp socket to interface");
            close(tcp_listenfd);
            return -1;
        }
        // 尝试设置端口可重用
        if (try_reuse_port(tcp_listenfd, config->enable_reuse_port) != 0) {
            close(tcp_listenfd);
            return -1;
        }
        // 尝试设置接收超时
        if (set_recv_timeout(tcp_listenfd, config->recv_timeout_sec, config->recv_timeout_ms) != 0) {
            close(tcp_listenfd);
            return -1;
        }
        // 设置为非阻塞模式
        setnonblocking(tcp_listenfd);
    }

    // Initialize UDP server if enabled
    if (enable_udp) {
        if (create_udp_server(&udpfd, ip, port) != 0) {
            fprintf(stderr, "Failed to create UDP server\n");
            if (tcp_listenfd != -1) close(tcp_listenfd);
            return -1;
        }
        // 绑定到指定网卡（如果有）
        if (try_bind_socket_to_interface(udpfd, config->bind_to_interface) != 0) {
            perror("bind udp socket to interface");
            close(udpfd);
            if (tcp_listenfd != -1) close(tcp_listenfd);
            return -1;
        }
        // 尝试设置端口可重用
        if (try_reuse_port(udpfd, config->enable_reuse_port) != 0) {
            close(udpfd);
            if (tcp_listenfd != -1) close(tcp_listenfd);
            return -1;
        }
        // 尝试设置UDP广播
        if (try_enable_udp_broadcast(udpfd, config->enable_udp_broadcast) != 0) {
            close(udpfd);
            if (tcp_listenfd != -1) close(tcp_listenfd);
            return -1;
        }
        // 尝试设置接收超时
        if (set_recv_timeout(udpfd, config->recv_timeout_sec, config->recv_timeout_ms) != 0) {
            close(udpfd);
            if (tcp_listenfd != -1) close(tcp_listenfd);
            return -1;
        }
        // 设置为非阻塞模式
        setnonblocking(udpfd);
    }

    // 初始化文件描述符集合
    FD_ZERO(&master_fds);

    // 添加TCP监听套接字到集合
    if (enable_tcp) {
        FD_SET(tcp_listenfd, &master_fds);
        max_fd = tcp_listenfd > max_fd ? tcp_listenfd : max_fd;
    }

    // 添加UDP套接字到集合
    if (enable_udp) {
        FD_SET(udpfd, &master_fds);
        max_fd = udpfd > max_fd ? udpfd : max_fd;
    }


    while (config->running) {
        // 复制主文件描述符集合到工作集合
        FD_ZERO(&read_fds);
        read_fds = master_fds;

        // 设置select超时
        tv.tv_sec = config->recv_timeout_sec;
        tv.tv_usec = config->recv_timeout_ms * 1000;

        // 等待事件发生
        int activity = select(max_fd + 1, &read_fds, NULL, NULL, &tv);

        if (activity < 0 && errno != EINTR) {
            perror("select error");
            // 短暂休眠避免忙等
            usleep(10000);
            continue;
        }

        // 超时情况，继续循环
        if (activity == 0) {
            continue;
        }

        // 检查TCP监听套接字
        if (enable_tcp && FD_ISSET(tcp_listenfd, &read_fds)) {
            // 接受新的TCP连接
            client_addrlength = sizeof(client_address);
            int connfd = accept(tcp_listenfd, (struct sockaddr*)&client_address, &client_addrlength);
            if (connfd < 0) {
                perror("tcp accept");
                continue;
            }

            // 设置为非阻塞模式
            setnonblocking(connfd);

            // 添加到客户端连接列表
            int slot = find_empty_slot(tcp_clients, TCP_CLIENT_MAX);
            if (slot >= 0) {
                tcp_clients[slot] = connfd;
                // 添加到文件描述符集合
                FD_SET(connfd, &master_fds);
                // 更新最大fd值
                if (connfd > max_fd) {
                    max_fd = connfd;
                }

                // 调用连接回调
                if (on_tcp_connect) {
                    on_tcp_connect(connfd, &client_address);
                }
            } else {
                // 连接数达到上限
                fprintf(stderr, "Warning: TCP client limit reached, connection rejected\n");
                close(connfd);
            }
        }

        // 检查UDP套接字
        if (enable_udp && FD_ISSET(udpfd, &read_fds)) {
            memset(buf_for_recv_udp, 0, buf_for_recv_udp_size);
            client_addrlength = sizeof(client_address);

            // 增加MSG_PEEK标志先检查数据包大小
            int packet_size = recvfrom(udpfd, NULL, 0, MSG_PEEK, (struct sockaddr*)&client_address, &client_addrlength);
            if (packet_size > buf_for_recv_udp_size) {
                // 记录警告日志
                fprintf(stderr, "Warning: UDP packet too large (%d bytes), buffer size: %d bytes\n", packet_size, buf_for_recv_udp_size);
            }

            ret = recvfrom(udpfd, buf_for_recv_udp, buf_for_recv_udp_size, 0, (struct sockaddr*)&client_address, &client_addrlength);
            if (ret > 0) {
                printf("UDP recv from %s:%d: ",
                       inet_ntoa(client_address.sin_addr),
                       ntohs(client_address.sin_port));
                for (int j = 0; j < ret; j++) {
                    printf("[%02x] ", buf_for_recv_udp[j]);
                }
                printf("\n");

                if (on_udp_data) {
                    on_udp_data(udpfd, &client_address, (const unsigned char *)buf_for_recv_udp, ret);
                }
            } else if (ret < 0) {
                if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
                    perror("udp recvfrom");
                }
            }
        }

        // 检查所有TCP客户端连接
        for (int i = 0; i < TCP_CLIENT_MAX; i++) {
            int sockfd = tcp_clients[i];

            if (sockfd > 0 && FD_ISSET(sockfd, &read_fds)) {
                while (config->running) {
                    memset(buf_for_recv_tcp, 0, buf_for_recv_tcp_size);
                    ret = recv(sockfd, buf_for_recv_tcp, buf_for_recv_tcp_size, 0);

                    if (ret < 0) {
                        if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                            break;
                        }
                        // 连接错误，关闭连接
                        close(sockfd);
                        FD_CLR(sockfd, &master_fds);
                        remove_client(tcp_clients, TCP_CLIENT_MAX, sockfd);

                        if (on_tcp_disconnect) {
                            on_tcp_disconnect(sockfd);
                        }
                        break;
                    } else if (ret == 0) {
                        // 客户端关闭连接
                        close(sockfd);
                        FD_CLR(sockfd, &master_fds);
                        remove_client(tcp_clients, TCP_CLIENT_MAX, sockfd);

                        if (on_tcp_disconnect) {
                            on_tcp_disconnect(sockfd);
                        }
                        break;
                    }

                    // 处理接收到的数据
                    if (on_tcp_data) {
                        on_tcp_data(sockfd, buf_for_recv_tcp, ret);
                    }

                    // 在LT模式下，不需要循环读取所有数据
                    break;
                }
            }
        }
    }

    // Cleanup - 正常情况下不会执行到这里
    for (int i = 0; i < TCP_CLIENT_MAX; i++) {
        if (tcp_clients[i] > 0) {
            close(tcp_clients[i]);
        }
    }
    if (tcp_listenfd != -1) close(tcp_listenfd);
    if (udpfd != -1) close(udpfd);
    return 0;
}

#ifdef __cplusplus
}
#endif

